package com.ccp.dev.extend.service;

import com.ccp.dev.core.basic.engine.FreemarkEngine;
import com.ccp.dev.core.basic.web.query.QueryFilter;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.core.util.DateFormatUtil;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.extend.dao.ExtendGeneratorDao;
import com.ccp.dev.extend.model.ExtendBaseModuleInfo;
import com.ccp.dev.extend.model.ExtendColumnInfo;
import com.ccp.dev.extend.model.ExtendTableInfo;
import com.ccp.dev.extend.util.ExtendGenUtils;
import com.ccp.dev.system.model.CodeGenConf;
import freemarker.template.TemplateException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 扩展的代码生成器服务类
 *
 * @author 创新中心-王明亮
 */
@Service
public class ExtendCodeGeneratorService {

    @Resource
    private ExtendGeneratorDao extendGeneratorDao;

    @Resource
    private FreemarkEngine freemarkEngine;

    @Value("classpath:/JSON/baseInfoJson.json")
    private org.springframework.core.io.Resource resource;

    /**
     * 查询数据库表信息
     *
     * @param queryFilter 表信息
     * @return 数据库表列表
     */
    public List<ExtendTableInfo> queryList(QueryFilter queryFilter) {
        return extendGeneratorDao.queryList(queryFilter);
    }

    /**
     * 根据表名称查询信息
     *
     * @param tableName 表名称
     * @return 表信息
     */
    public ExtendTableInfo getTableByName(String tableName) {
        return extendGeneratorDao.getTableByName(tableName);
    }


    /**
     * 根据表名称查询列信息
     *
     * @param tableName 表名称
     * @return 列信息
     */
    public List<ExtendColumnInfo> getTableColumnsByName(String tableName) {
        List<ExtendColumnInfo> columns = extendGeneratorDao.getTableColumnsByName(tableName);
        return ExtendGenUtils.columnsInfoOfSetting(columns);
    }

    /**
     * 根据表名称获取约束列
     *
     * @param tableName 表名称
     * @return
     */
    public List<ExtendColumnInfo> getTableColumnKeyByTableName(String tableName) {
        List<ExtendColumnInfo> columnKey = extendGeneratorDao.getTableColumnsByName(tableName);
        return ExtendGenUtils.columnsInfoOfSetting(columnKey);
    }

    /**
     * 获取表信息约束列
     *
     * @param table TableInfo信息
     * @return 带有约束列的信息
     */
    public ExtendColumnInfo getTablePrimaryKey(ExtendTableInfo table) {
        return extendGeneratorDao.getTableColumnKeyByTableName(table);
    }

    /**
     * 根据表名称查询列信息(带分页)
     *
     * @param queryFilter 表信息
     * @return 列信息
     */
    public List<ExtendColumnInfo> queryCols(QueryFilter queryFilter) {
        return extendGeneratorDao.queryCols(queryFilter);
    }

    /**
     * 功能描述:  生成代码
     *
     * @param: baseModuleInfo 模板基本信息对象
     * @return: byte[]
     * @auther: dfz
     * @date: 2019/5/22 14:34
     */
    public byte[] generatorCode(ExtendBaseModuleInfo baseModuleInfo, List<ExtendColumnInfo> columns, String selectFlow) throws IOException, TemplateException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);
        String tableName = baseModuleInfo.getTableName();
        // 查询表信息
        ExtendTableInfo table = extendGeneratorDao.getTableByName(tableName);
        if (columns == null || columns.size() == 0) {
            // 查询列信息
            columns = extendGeneratorDao.getTableColumnsByName(tableName);
        }
        try {
            // 生成代码
            generatorCode(baseModuleInfo, table, columns, zip, selectFlow);
        } catch (Exception e) {
            throw e;
        } finally {
            if (zip != null) {
                //关流
                zip.close();
            }
        }
        return outputStream.toByteArray();
    }

    /**
     * 功能描述: 批量生成代码
     *
     * @param: baseModuleInfo
     * @return:
     * @auther: dfz
     * @date: 2019/5/22 14:34
     */
    public byte[] batchGeneratorCode(ExtendBaseModuleInfo baseModuleInfo, String selectFlow) throws IOException, TemplateException {

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);
        String[] tableNames = baseModuleInfo.getTableName().split(",");
        try {
            for (String tableName : tableNames) {
                // 查询表信息
                ExtendTableInfo table = extendGeneratorDao.getTableByName(tableName);
                // 查询列信息
                List<ExtendColumnInfo> columns = extendGeneratorDao.getTableColumnsByName(tableName);
                table.setColumns(columns);
                if (StringUtil.isEmpty(table.getTableComment())) {
                    table.setTableComment(table.getTableName());
                }
                //驼峰命名
                table.setClassForClassName(StringUtil.convertToCamelCase(table.getTableName()));
                //取消首字母大写
                table.setClassForPrefix(StringUtil.convertToCamelFirstLowerCase(table.getTableName()));
                ExtendBaseModuleInfo tmpModuleInfo = new ExtendBaseModuleInfo(table, columns);
                //表名称
                tmpModuleInfo.setTableName(tableName);
                //基本包路径
                tmpModuleInfo.setBasePackage(baseModuleInfo.getBasePackage());
                //模块名称
                tmpModuleInfo.setModuleName(baseModuleInfo.getModuleName());
                //作者信息
                tmpModuleInfo.setAuthor(baseModuleInfo.getAuthor());
                //是否完整页面
                tmpModuleInfo.setShowFull(baseModuleInfo.getShowFull());
                //设置打开方式
                tmpModuleInfo.setSelectOpenMode(baseModuleInfo.getSelectOpenMode());
                //当选择跳转方式后,选择模板的数据
                tmpModuleInfo.setSelectColumn(baseModuleInfo.getSelectColumn());
                // 生成代码
                generatorCode(tmpModuleInfo, table, columns, zip, selectFlow);
            }
        } catch (Exception e) {
            //todo 此处的处理是否可以优化
            throw e;
        } finally {
            if (zip != null) {
                //关流
                zip.close();
            }
        }
        return outputStream.toByteArray();
    }


    /**
     * 功能描述: 生成代码
     *
     * @param: baseModuleInfo  模板基本信息
     * @param: table  表名称
     * @param: columns  列信息
     * @param: zip  zip输出流
     * @return: void
     * @auther: dfz
     * @date: 2019/5/17 8:52
     */
    public void generatorCode(ExtendBaseModuleInfo baseModuleInfo, ExtendTableInfo table, List<ExtendColumnInfo> columns, ZipOutputStream zip, String selectFlow) throws IOException, TemplateException {
        //表的基本信息转换
        processTableInfo(baseModuleInfo, table, columns);
        String className = baseModuleInfo.getClassForClassName();
        if (StringUtil.isEmpty(className)) {
            //没有配置自定义类名，默认根据表名按照驼峰命名
            baseModuleInfo.setClassForClassName(table.getClassForClassName());
            baseModuleInfo.setClassForPrefix(table.getClassForPrefix());
        } else {
            //首字母小写
            baseModuleInfo.setClassForPrefix(StringUtil.convertToCamelFirstLowerCase(className));
        }
        //设置表描述
        if (StringUtil.isEmpty(table.getTableComment())) {
            baseModuleInfo.setTableComment(table.getTableName());
        } else {
            baseModuleInfo.setTableComment(table.getTableComment());
        }
        //设置attrNameForMethod
        if ((StringUtil.isEmpty(baseModuleInfo.getPrimaryKey().getAttrNameForMethod())
                && StringUtil.isNotEmpty(baseModuleInfo.getPrimaryKey().getAttrNameForProperty()))
                || !(baseModuleInfo.getPrimaryKey().getAttrNameForProperty().equals(baseModuleInfo.getPrimaryKey().getAttrNameForMethod()))) {
            baseModuleInfo.getPrimaryKey().setAttrNameForMethod(StringUtil.makeFirstLetterUpperCase(baseModuleInfo.getPrimaryKey().getAttrNameForProperty()));
        }
        //若Java类型为空,则设置Java类型与jdbc类型
        if (StringUtil.isEmpty(baseModuleInfo.getPrimaryKey().getAttrType())) {
            String attrType = ExtendGenUtils.javaTypeMap.get(baseModuleInfo.getPrimaryKey().getDataType());
            baseModuleInfo.getPrimaryKey().setAttrType(attrType.trim());
            //设置jdbc类型
            String jdbcType = ExtendGenUtils.jdbcTypeMap.get(baseModuleInfo.getPrimaryKey().getDataType());
            baseModuleInfo.getPrimaryKey().setJdbcType(jdbcType);
        }
        //设置表的列信息
        baseModuleInfo.setColumns(columns);
        //设置创建时间
        baseModuleInfo.setDatetime(DateFormatUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        //模块名
        String moduleName = baseModuleInfo.getModuleName();
        baseModuleInfo.setModuleViewName(moduleName.toUpperCase());

        CodeGenConf codeGenConf = new CodeGenConf();

        //显示与隐藏的列数
        int showColumnSize = 0;
        if (BeanUtils.isNotEmpty(baseModuleInfo.getShowColumns())) {
            showColumnSize = baseModuleInfo.getShowColumns().size();
        }

        int hideColumnSize = 0;
        if (BeanUtils.isNotEmpty(baseModuleInfo.getHideColumns())) {
            hideColumnSize = baseModuleInfo.getHideColumns().size();
        }

        codeGenConf.setColumnSize(showColumnSize);
        codeGenConf.setHideColumnSize(hideColumnSize);

        // 用来处理多列布局的换行
        int result = 0;
        if (showColumnSize<=ExtendGenUtils.FIELDSNUM) {
            result=1;
        }
        else if(showColumnSize>ExtendGenUtils.FIELDSNUM){
            result=3;
        }


        //显示列
        if (showColumnSize % result == 0) {
            codeGenConf.setRowSize(showColumnSize / result);
        } else {
            codeGenConf.setRowSize((showColumnSize / result) + 1);
        }

        //隐藏列
        if (hideColumnSize % result == 0) {
            codeGenConf.setHideRowSize(hideColumnSize / result);
        } else {
            codeGenConf.setHideRowSize((hideColumnSize / result) + 1);
        }

        codeGenConf.setColSize(result);

        //封装基本信息
        Map model = new HashMap();
        model.put("baseInfo", baseModuleInfo);
        model.put("selectFlow", selectFlow);
        model.put("codeGenConf", codeGenConf);

        //获取模板列表
        List<String> templatePaths = ExtendGenUtils.getTemplates(baseModuleInfo, selectFlow);

        for (String path : templatePaths) {
            String ftlStr = freemarkEngine.mergeTemplateIntoString(path, model);
            String fileType = path.substring(path.lastIndexOf("/") + 1, path.length() - 4);
            String filePath = ExtendGenUtils.getFilePath(baseModuleInfo, fileType);
            zip.putNextEntry(new ZipEntry(filePath));
            IOUtils.write(ftlStr, zip, "utf-8");
            zip.closeEntry();
        }
    }

    /**
     * 功能描述: 转换tableInfo的基本信息
     *
     * @param:
     * @return:
     * @auther: dfz
     * @date: 2019/5/17 11:02
     */
    public void processTableInfo(ExtendBaseModuleInfo baseModuleInfo, ExtendTableInfo table, List<ExtendColumnInfo> columns) {
        String tableName = table.getTableName();
        //驼峰命名
        table.setClassForClassName(StringUtil.convertToCamelCase(tableName));
        //取消首字母大写
        table.setClassForPrefix(StringUtil.convertToCamelFirstLowerCase(tableName));
        // 列信息
        table.setColumns(ExtendGenUtils.columnsInfoOfSetting(columns));
        if (StringUtil.isEmpty(baseModuleInfo.getPrimaryKey())) {
            for (ExtendColumnInfo column : columns) {
                if (StringUtil.isNotEmpty(column.getColumnkey()) && "PRIMARY".equals(column.getColumnkey())) {
                    String attrName = column.getAttrNameForProperty();
                    if (attrName.length() > 1) {
                        char charName = attrName.charAt(1);
                        if (Character.isUpperCase(charName)) {
                            attrName = StringUtil.convertToCamelFirstLowerCase(column.getAttrNameForProperty());
                        } else {
                            attrName = StringUtil.makeFirstLetterUpperCase(column.getAttrNameForProperty());
                        }
                    }

                    column.setAttrNameForMethod(StringUtil.makeFirstLetterUpperCase(attrName));
                    column.setAttrNameForProperty(StringUtils.uncapitalize(attrName));
                    baseModuleInfo.setPrimaryKey(column);
                    baseModuleInfo.getPrimaryKey().setAttrNameForMethod(attrName);
                } else {
                    String attrName = column.getAttrNameForProperty();
                    if (attrName.length() > 1) {
                        char charName = attrName.charAt(1);
                        if (Character.isUpperCase(charName)) {
                            attrName = StringUtil.convertToCamelFirstLowerCase(column.getAttrNameForProperty());
                        } else {
                            attrName = StringUtil.makeFirstLetterUpperCase(column.getAttrNameForProperty());
                        }
                    }

                    column.setAttrNameForMethod(StringUtil.makeFirstLetterUpperCase(attrName));
                    column.setAttrNameForProperty(StringUtils.uncapitalize(attrName));
                }
            }
            if (StringUtil.isEmpty(baseModuleInfo.getPrimaryKey())) {
                baseModuleInfo.setPrimaryKey(table.getColumnsFirst());
            }
            return;
        } else {
            for (ExtendColumnInfo column : columns) {
                String attrName = column.getAttrNameForProperty();
                if (attrName.length() > 1) {
                    char charName = attrName.charAt(1);
                    if (Character.isUpperCase(charName)) {
                        attrName = StringUtil.convertToCamelFirstLowerCase(column.getAttrNameForProperty());
                    } else {
                        attrName = StringUtil.makeFirstLetterUpperCase(column.getAttrNameForProperty());
                    }
                }

                column.setAttrNameForMethod(StringUtil.makeFirstLetterUpperCase(attrName));
                column.setAttrNameForProperty(StringUtils.uncapitalize(attrName));
            }
        }
        //区分显示列与隐藏列
        List<ExtendColumnInfo> hideColumns = new ArrayList<>();
        List<ExtendColumnInfo> showColumns = new ArrayList<>();
        for (ExtendColumnInfo column : columns) {
            if (column.getAsFormCol()) {
                showColumns.add(column);
            } else {
                hideColumns.add(column);
            }
        }
        baseModuleInfo.setHideColumns(hideColumns);
        baseModuleInfo.setShowColumns(showColumns);

    }
}
